import { delay, dpiFromFileName, getPageDpi, ensureExtName, dataURItoBlob } from '@/common/utils'
import { ComputerVisionType } from '@/common/cv_utils';
import { activateTab } from '@/common/tab_utils'
import { getStorageManager } from '@/file_storage'
import { PageInfo, CaptureScreenshotService, scaleDataURI } from '@/common/capture_screenshot'
import { Rect, Point } from '@/common/types'
import * as CONSTANT from '@/common/constant'
import { getState } from '@/common/ext_storage_state'
import { askPlayTab } from '@/common/ipc/ipc'

export type SearchVisionParams = {
  visionFileName: string;
  minSimilarity: number;
  command: any;
  cvScope: ComputerVisionType;
  devicePixelRatio: number;
  captureScreenshotService: CaptureScreenshotService;
  searchArea?: string;
  storedImageRect?: Rect;
}

export type SearchVisionResult = {
  regions: any[];
  imageInfo: {
    source: any;
    path: string;
  }
}

type GetScreenshotInSearchAreaParams = {
  searchArea: string;
  dpiScale: number;
  devicePixelRatio: number;
  captureScreenshotService: CaptureScreenshotService;
  storedImageRect?: Rect;
}

export function saveDataUrlToScreenshot(fileName: string, dataUrl: string): Promise<void> {
  return getStorageManager()
    .getScreenshotStorage()
    .overwrite(
      ensureExtName('.png', fileName),
      dataURItoBlob(dataUrl)
    )
  // TODO:
  // getPanelTabIpc()
  // .then(panelIpc => {
  //   return panelIpc.ask('RESTORE_SCREENSHOTS')
  // })
}

export function saveDataUrlToLastScreenshot(dataUrl: string): Promise<void> {
  return saveDataUrlToScreenshot(CONSTANT.LAST_SCREENSHOT_FILE_NAME, dataUrl)
}

export function saveDataUrlToLastDesktopScreenshot(dataUrl: string): Promise<void> {
  return saveDataUrlToScreenshot(CONSTANT.LAST_DESKTOP_SCREENSHOT_FILE_NAME, dataUrl)
}

export function getScreenshotInSearchArea({ searchArea, storedImageRect, dpiScale, devicePixelRatio, captureScreenshotService }: GetScreenshotInSearchAreaParams) {
  // Take png searh area as rect, it should have set `storedImageRect` in advance
  if (/\.png/.test(searchArea)) {
    searchArea = 'rect'
  }

  const capture = (tabId: number) => {
    switch (searchArea) {
      case 'viewport':
        return Promise.all([
          askPlayTab('SCREENSHOT_PAGE_INFO', {}, CONSTANT.CS_IPC_TIMEOUT),
          captureScreenshotService.captureScreen(tabId, devicePixelRatio)
        ])
          .then(([pageInfo, dataUrl]: any) => {
            saveDataUrlToLastScreenshot(dataUrl)

            return {
              offset: {
                x: pageInfo.originalX,
                y: pageInfo.originalY
              },
              viewportOffset: {
                x: 0,
                y: 0
              },
              dataUrl

            }
          })

      case 'full': {
        return Promise.all([
          askPlayTab('SCREENSHOT_PAGE_INFO', {}, CONSTANT.CS_IPC_TIMEOUT),
          captureScreenshotService.captureFullScreen(tabId, {
            startCapture: (): Promise<PageInfo> => {
              return askPlayTab('START_CAPTURE_FULL_SCREENSHOT', {}, CONSTANT.CS_IPC_TIMEOUT)
            },
            endCapture: (pageInfo: PageInfo): Promise<boolean> => {
              return askPlayTab('END_CAPTURE_FULL_SCREENSHOT', { pageInfo }, CONSTANT.CS_IPC_TIMEOUT)
            },
            scrollPage: (offset: Point): Promise<Point> => {
              return askPlayTab('SCROLL_PAGE', { offset }, CONSTANT.CS_IPC_TIMEOUT)
            }
          })
        ])
          .then(([pageInfo, dataUrl]: any) => {
            saveDataUrlToLastScreenshot(dataUrl as string)
            return {
              dataUrl,
              offset: {
                x: 0,
                y: 0
              },
              viewportOffset: {
                x: -1 * pageInfo.originalX,
                y: -1 * pageInfo.originalY
              }
            }
          })
      }

      case 'rect': {
        // Note: in this mode, `storedImageRect` is viewport based coordinates
        if (!storedImageRect) {
          throw new Error('rect mode: !storedImageRect should not be empty')
        }

        return askPlayTab('SCREENSHOT_PAGE_INFO')
          .then((pageInfo: PageInfo) => {
            return captureScreenshotService.captureScreenInSelectionSimple(tabId, {
              rect: storedImageRect,
              devicePixelRatio: pageInfo.devicePixelRatio
            })
              .then((dataUrl: string | Blob) => {
                saveDataUrlToLastScreenshot(dataUrl as string)

                return ({
                  dataUrl,
                  offset: {
                    x: storedImageRect.x + pageInfo.originalX,
                    y: storedImageRect.y + pageInfo.originalY
                  },
                  viewportOffset: {
                    x: storedImageRect.x,
                    y: storedImageRect.y
                  }
                })
              })
          })
      }

      default: {
        if (/^element:/i.test(searchArea)) {
          // Note: in this mode, `storedImageRect` is document based coordinates
          if (!storedImageRect) {
            throw new Error('!storedImageRect should not be empty')
          }

          const fileName = ensureExtName('.png', CONSTANT.LAST_SCREENSHOT_FILE_NAME)

          return Promise.all([
            askPlayTab('SCREENSHOT_PAGE_INFO', {}, CONSTANT.CS_IPC_TIMEOUT),
            getStorageManager()
              .getScreenshotStorage()
              .read(fileName, 'DataURL')
          ])
            .then(([pageInfo, dataUrl]: any) => {
              return {
                dataUrl,
                offset: {
                  x: storedImageRect.x,
                  y: storedImageRect.y
                },
                viewportOffset: {
                  x: storedImageRect.x - pageInfo.originalX,
                  y: storedImageRect.y - pageInfo.originalY
                }
              }
            })
        }

        throw new Error(`Unsupported searchArea '${searchArea}'`)
      }
    }
  }

  return Promise.all([getState()])
    .then(([state]) => {
      const toPlayTabId = state.tabIds.toPlay

      return activateTab(toPlayTabId, true)
        .then(() => delay(() => { }, CONSTANT.SCREENSHOT_DELAY))
        .then(() => capture(toPlayTabId))
        .then(obj => {
          return scaleDataURI(obj.dataUrl, dpiScale)
            .then(dataUrl => ({
              dataUrl,
              offset: obj.offset,
              viewportOffset: obj.viewportOffset
            }))
        })
    })
}
